package service

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	baseStore "gitee.com/zaiqiang231/go-base-app/base_app/store"
	sessionModel "gitee.com/zaiqiang231/go-base-session/app/model"
	"gitee.com/zaiqiang231/zcamp-service-camp/app/model"
	"gitee.com/zaiqiang231/zcamp-service-camp/app/model/req"
	remoteRpc "gitee.com/zaiqiang231/zcamp-service-camp/app/rpc/remote"
	"gitee.com/zaiqiang231/zcamp-service-camp/app/store"
	userProto "gitee.com/zaiqiang231/zcamp-service-user/app/rpc/proto"
	"gorm.io/gorm"
	"strings"
)

type ServiceCamp struct{}

var ServiceCampInstance = new(ServiceCamp)

func (service *ServiceCamp) Create(item *req.CampCreateReq, conditions []int64) (err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		err = db.Transaction(func(tx *gorm.DB) error {
			txErr := tx.Create(&item).Error
			if txErr != nil {
				return txErr
			}

			txErr = tx.Model(model.CampMapCondition{}).Where("camp_id = ?", item.ID).Unscoped().Delete(&[]model.CampMapCondition{}).Error
			if txErr != nil {
				return txErr
			}

			if len(conditions) > 0 {
				for i := 0; i < len(conditions); i++ {
					txErr := tx.Create(&model.CampMapCondition{
						CampID:      int64(item.ID),
						ConditionID: conditions[i],
					}).Error
					if txErr != nil {
						return txErr
					}
				}
			}

			return nil
		})

	})
	return
}

func (service *ServiceCamp) GetList(info req.CampListReq) (list interface{}, total int64, err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		limit := info.PageSize
		offset := info.PageSize * (info.Page - 1)
		var tempDb = db
		if info.ID != 0 {
			tempDb = tempDb.Where("id = ?", info.ID)
		}
		if info.CampName != "" {
			tempDb = tempDb.Where("camp_name LIKE ?", "%"+info.CampName+"%")
		}
		if info.Status != 0 {
			tempDb = tempDb.Where("status = ?", info.Status)
		}
		var tmpList []model.BaseCampInfo
		err = tempDb.Model(&model.BaseCampInfo{}).Count(&total).Error
		if err != nil {
			return
		}
		err = tempDb.Model(&model.BaseCampInfo{}).Offset(offset).Limit(limit).Find(&tmpList).Error
		if err != nil {
			return
		}
		list = tmpList
	})
	return
}

func (service *ServiceCamp) SearchList(ctx context.Context, atom sessionModel.Atom, info req.CampListSearchReq) (list interface{}, total int64, err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		limit := info.PageSize
		offset := info.PageSize * (info.Page - 1)
		var tempDb = db.Table(model.BaseCampInfo{}.TableName())
		if info.Keyword != "" {
			tempDb = tempDb.Where("camp_name LIKE ?", "%"+info.Keyword+"%")
		}
		tempDb = tempDb.Where("status = ?", model.DataStatusOnline)

		if info.Longitude != "" && info.Latitude != "" {
			//selectSql := fmt.Sprintf("*, (6371 * acos(cos(radians(%v))*cos(radians(latitude))*cos(radians(longitude)-radians(%v))+sin(radians(%v))*sin(radians(latitude)))) AS distance", info.Latitude, info.Longitude, info.Latitude)
			//selectSql := fmt.Sprintf("*,round(6371.004 * 2 * ASIN( SQRT( POW( SIN((%v * PI() / 180 - latitude * PI() / 180) / 2),2) + COS(%v * PI() / 180) * COS(latitude * PI() / 180) * POW(SIN((%v * PI() / 180 - longitude * PI() / 180 ) / 2 ),2))) * 1000) AS distance", info.Latitude, info.Latitude, info.Longitude)
			//selectSql := fmt.Sprintf("*, ROUND((6371000 * acos(cos(radians(%v))*cos(radians(latitude))*cos(radians(longitude)-radians(%v))+sin(radians(%v))*sin(radians(latitude))))) AS distance", info.Latitude, info.Longitude, info.Latitude)
			selectSql := fmt.Sprintf("*, CAST((6371000 * acos(cos(radians(%v))* cos(radians(latitude))* cos(radians(longitude) - radians(%v))+ sin(radians(%v))* sin(radians(latitude)))) AS UNSIGNED) AS distance", info.Latitude, info.Longitude, info.Latitude)
			tempDb = tempDb.Select(selectSql)
		} else {
			selectSql := "*, 0 AS distance"
			tempDb = tempDb.Select(selectSql)
		}

		switch info.ListSortType {
		case model.ListSortTypeDistance:
			tempDb = tempDb.Order("distance, id")
		case model.ListSortTypePopularity:
			tempDb = tempDb.Order("`sales` DESC ,`distance` ASC, id")
		case model.ListSortTypePraise:
			tempDb = tempDb.Order("`score` DESC ,`distance` ASC, id")
		default:
			tempDb = tempDb.Order("distance,id")
		}

		if info.ConditionList != nil && len(info.ConditionList) > 0 {
			for _, v := range info.ConditionList { //按条件搜素字符
				tempDb = tempDb.Where(fmt.Sprintf("conditions regexp '[\\\\[,]%v[,\\\\]]'", v))
			}
		}

		if info.AdCode != "" {
			adCodes, temperr := ServiceDistrictInstance.GetAdCodeList(info.AdCode)
			err = temperr
			if err != nil {
				return
			}
			tempDb = tempDb.Where("district_id in (?)", adCodes)
		}

		var tmpList []req.CampListSearchRes
		err = tempDb.Count(&total).Error
		if err != nil {
			return
		}
		err = tempDb.Offset(offset).Limit(limit).Find(&tmpList).Error
		if err != nil {
			return
		}

		for i := range tmpList {
			//查询营地是否收藏
			isCollect, _ := store.IsCollect(ctx, atom.Uid, int64(tmpList[i].ID))
			tmpList[i].IsCollect = isCollect
		}

		list = tmpList
	})
	return
}

func (service *ServiceCamp) RankList(info req.CampListRankReq) (list interface{}, total int64, err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		limit := info.PageSize
		offset := info.PageSize * (info.Page - 1)
		var tempDb = db.Table(model.BaseCampInfo{}.TableName())

		tempDb = tempDb.Where("status = ?", model.DataStatusOnline)

		if info.Longitude != "" && info.Latitude != "" {
			//selectSql := fmt.Sprintf("*, (6371 * acos(cos(radians(%v))*cos(radians(latitude))*cos(radians(longitude)-radians(%v))+sin(radians(%v))*sin(radians(latitude)))) AS distance", info.Latitude, info.Longitude, info.Latitude)
			//selectSql := fmt.Sprintf("*,round(6371.004 * 2 * ASIN( SQRT( POW( SIN((%v * PI() / 180 - latitude * PI() / 180) / 2),2) + COS(%v * PI() / 180) * COS(latitude * PI() / 180) * POW(SIN((%v * PI() / 180 - longitude * PI() / 180 ) / 2 ),2))) * 1000) AS distance", info.Latitude, info.Latitude, info.Longitude)
			//selectSql := fmt.Sprintf("*, ROUND((6371000 * acos(cos(radians(%v))*cos(radians(latitude))*cos(radians(longitude)-radians(%v))+sin(radians(%v))*sin(radians(latitude))))) AS distance", info.Latitude, info.Longitude, info.Latitude)
			selectSql := fmt.Sprintf("*, CAST((6371000 * acos(cos(radians(%v))* cos(radians(latitude))* cos(radians(longitude) - radians(%v))+ sin(radians(%v))* sin(radians(latitude)))) AS UNSIGNED) AS distance", info.Latitude, info.Longitude, info.Latitude)
			tempDb = tempDb.Select(selectSql)
		} else {
			selectSql := "*, 0 AS distance"
			tempDb = tempDb.Select(selectSql)
		}

		if info.AdCode != "" {
			adCodes, temperr := ServiceDistrictInstance.GetAdCodeList(info.AdCode)
			err = temperr
			if err != nil {
				return
			}
			tempDb = tempDb.Where("district_id in (?)", adCodes)
		}

		tempDb = tempDb.Order("`sales` DESC ,`distance` ASC, id")

		var tmpList []req.CampListSearchRes
		err = tempDb.Count(&total).Error
		if err != nil {
			return
		}
		err = tempDb.Offset(offset).Limit(limit).Find(&tmpList).Error
		if err != nil {
			return
		}
		list = tmpList
	})
	return
}

func (service *ServiceCamp) DeleteList(info req.IdsReq) (err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		var tmpList []model.BaseCampInfo
		err = db.Model(&model.BaseCampInfo{}).Where("id in ?", info.Ids).Find(&tmpList).Delete(&tmpList).Error
	})
	return
}

func (service *ServiceCamp) UpdateForMap(info map[string]interface{}, conditions []int64) (err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {

		err = db.Transaction(func(tx *gorm.DB) error {
			var old model.BaseCampInfo
			var txErr error
			if errors.Is(tx.Where("id = ?", info["id"]).First(&old).Error, gorm.ErrRecordNotFound) {
				txErr = errors.New("原记录不存在")
			}
			if txErr != nil {
				return txErr
			}
			delete(info, "updated_at")
			txErr = tx.Model(&old).Omit("id", "created_at", "deleted_at").Updates(info).Error
			if txErr != nil {
				return txErr
			}

			txErr = tx.Model(model.CampMapCondition{}).Where("camp_id = ?", old.ID).Unscoped().Delete(&[]model.CampMapCondition{}).Error
			if txErr != nil {
				return txErr
			}

			if len(conditions) > 0 {
				for i := 0; i < len(conditions); i++ {
					txErr := tx.Create(&model.CampMapCondition{
						CampID:      int64(old.ID),
						ConditionID: conditions[i],
					}).Error
					if txErr != nil {
						return txErr
					}
				}
			}

			return nil
		})

	})
	return err
}

func (service *ServiceCamp) UpdateForReq(req req.CampUpdateReq) (err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		var old model.BaseCampInfo
		if errors.Is(db.Where("id = ?", req.ID).First(&old).Error, gorm.ErrRecordNotFound) {
			err = errors.New("原记录不存在")
		}
		if err != nil {
			return
		}
		err = db.Model(&old).Omit("id", "created_at", "deleted_at").Updates(req.BaseCampInfo).Error
	})
	return err
}

func (service *ServiceCamp) CampNationNum(info req.CampNationNumReq) (list []interface{}, err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		provinceList, _, temperr := ServiceDistrictInstance.GetProvinceAndCityList()
		if temperr != nil {
			err = temperr
			return
		}
		for i := 0; i < len(provinceList); i++ {
			center := strings.Split(provinceList[i].Center, ",")
			_, total, temperr := service.DistrictCampList(provinceList[i].AdCode, info.ConditionList)
			if temperr != nil {
				err = temperr
				return
			}
			list = append(list, model.NationNum{
				Id:        int64(provinceList[i].ID),
				AdCode:    provinceList[i].AdCode,
				Name:      provinceList[i].Name,
				Longitude: center[0],
				Latitude:  center[1],
				CampNum:   total,
			})
		}
	})
	return
}

func (service *ServiceCamp) DistrictCampList(adcode string, conditions []int) (list interface{}, total int64, err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		var tempDb = db.Table(model.BaseCampInfo{}.TableName())
		tempDb = tempDb.Where("status = ?", model.DataStatusOnline)

		adCodes, temperr := ServiceDistrictInstance.GetAdCodeList(adcode)
		err = temperr
		if err != nil {
			return
		}
		tempDb = tempDb.Where("district_id in (?)", adCodes).Order("id")

		if len(conditions) > 0 {
			for _, v := range conditions { //按条件搜素字符
				tempDb = tempDb.Where(fmt.Sprintf("conditions regexp '[\\\\[,]%v[,\\\\]]'", v))
			}
		}

		var tmpList []model.BaseCampInfo
		err = tempDb.Count(&total).Find(&tmpList).Error
		if err != nil {
			return
		}
		list = tmpList
	})
	return
}

func (service *ServiceCamp) CampDetail(ctx context.Context, atom sessionModel.Atom, campId int64) (data interface{}, err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		var resp = new(req.CampDetailResp)
		var campInfo model.BaseCampInfo
		var tempDb = db.Table(model.BaseCampInfo{}.TableName()).Where("status = ?", model.DataStatusOnline).Where("id = ?", campId)
		err = tempDb.Find(&campInfo).Error
		if err != nil {
			return
		}

		userResponse, temperr := remoteRpc.GetUserRpc().UserRpcServiceClient.GetUserInfo(ctx, &userProto.UserInfoRequest{
			Uid: campInfo.Uid,
		})
		if temperr != nil {
			err = temperr
			return
		}

		var conditionList = make([]int64, 0)
		err = json.Unmarshal([]byte(campInfo.Conditions), &conditionList)
		if err != nil {
			return
		}
		campDetailConditionList, temperr := ServiceConditionInstance.CampDetailCondition(conditionList)
		if temperr != nil {
			err = temperr
			return
		}

		resp.Camp = req.CampDetail{
			BaseCampInfo:  campInfo,
			ConditionList: campDetailConditionList,
		}
		resp.User = model.UserInfo{
			Uid:       userResponse.Uid,
			NickName:  userResponse.NickName,
			HeaderImg: userResponse.HeaderImg,
		}

		//查询营地是否收藏
		if atom.Uid > 0 {
			isCollect, _ := store.IsCollect(ctx, atom.Uid, campId)
			resp.IsCollect = isCollect
		}

		data = resp
	})
	return
}

func (service *ServiceCamp) GetBaseCampInfo(campId int64) (data *model.BaseCampInfo, err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		var campInfo model.BaseCampInfo
		var tempDb = db.Table(model.BaseCampInfo{}.TableName()).Where("status = ?", model.DataStatusOnline).Where("id = ?", campId)
		err = tempDb.Find(&campInfo).Error
		if err != nil {
			return
		}
		data = &campInfo
	})
	return
}

func (service *ServiceCamp) SetCollectInfo(ctx context.Context, request req.CollectReq, uid int64) error {
	if request.Campid == 0 || (request.Status != 0 && request.Status != 1) {
		return errors.New("参数错误")
	}
	if request.Status == 0 { //加入收藏

		err := store.SetCollectCache(ctx, uint64(uid), request.Campid)
		if err != nil {
			return errors.New(fmt.Sprintf("SetCollectCache error:%v", err))
		}
	} else if request.Status == 1 { //取消收藏
		err := store.RemCollectCache(ctx, uid, request.Campid)
		if err != nil {
			return errors.New(fmt.Sprintf("RemCollectCache error:%v", err))
		}
	}
	return nil
}

func (service *ServiceCamp) GetGreenStatusInfo(uid int64) (status int) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		var greenStatus model.GreenStatus
		var tempDb = db.Table(model.GreenStatus{}.TableName()).Where("uid = ?", uid)
		err := tempDb.First(&greenStatus).Error
		if err != nil {
			status = 0
			return
		}
		status = 1
	})
	return
}
